package regEx.finiteAutomata;

/**
 * State.java
 *
 * This class is a data structure needed to define a state in a
 * finite automaton
 */

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

public class State implements Comparable<State> {

    /** Unique ID of this state */
    public int id;

    /** List of transitions between states */
    public ArrayList<Transition> transitionsArray;

    /** Is this state an accept state */
    private boolean acceptState;

    /**
     * Create a new state
     * @param name
     */
    public State(int id) {
        this.acceptState = false;
        this.id = id;
        this.transitionsArray = new ArrayList<Transition>();
    }

    public void addTransition(final char transitionChar, final State toState) {
        this.transitionsArray.add(new Transition(transitionChar, toState));
    }

    /**
     * Overriding the compare function will allow use for collections
     * that use comparisons
     */
    public int compareTo(State otherState) {
        return Integer.valueOf(this.id).compareTo(otherState.id);
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public ArrayList<Transition> getTransitionsArray() {
        return transitionsArray;
    }

    public void setTransitionsArray(ArrayList<Transition> transitionsArray) {
        this.transitionsArray = transitionsArray;
    }

    public String toString() {
        return this.id + "";
    }

    /**
     * Computes the e-closure for this state.
     * @return a list of states in this closure.  this will include 'this' state
     */
    public Set<State> eClosure() {
        Set<State> closure = new HashSet<State>();

        closure.add(this);

        for (Transition t : this.transitionsArray) {
            if (t.getTransitionValue() == 'e') {
                t.getToState().eClosure(closure);
            }
        }

        return closure;
    }

    /**
     * Helper method for eClosure that will basically UNION the e-Closures of all the states that
     * are reachable from this eClosure.
     */
    private void eClosure(Set<State> closure) {
        if (closure.contains(this)) {
            return;
        }

        closure.add(this);

        for (Transition t : this.transitionsArray) {
            if (t.getTransitionValue() == 'e') {
                t.getToState().eClosure(closure);
            }
        }
    }

    /**
     * Get the next state for the given input.  If there are no transitions for the input
     * string then return null
     *
     * @param input a char to transition with.
     * @return the state that will transition
     */
    public State evaluateInput(char input) {
        for (Transition t : this.transitionsArray) {
            if (t.getTransitionValue() == input) {
                return t.getToState();
            }
        }

        return null;
    }

    public boolean isAcceptState() {
        return this.acceptState;
    }

    public void setAcceptState(boolean b) {
        this.acceptState = true;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }

        return this.getId() == ((State)obj).getId();
    }

}
